#include "list.h"

#include "interrupt.h"
#include "print.h"

/* 初始化双向链表list */
void list_init(struct list* list)
{
  list->head.prev = NULL;
  list->head.next = &list->tail;
  list->tail.prev = &list->head;
  list->tail.next = NULL;
}

/* 把链表元素elem插入在元素before之前 */
void list_insert_before(struct list_elem* before, struct list_elem* elem)
{
  enum intr_status old_status =intr_disable();
  // 未来这个链表结点插入是用于修改task_struck队列的，这是个公共资源，所以需要不被切换走

  /* 将before前驱元素的后继元素更新为elem, 暂时使before脱离链表*/
  before->prev->next = elem;

  /* 更新elem自己的前驱结点为before的前驱,
   * 更新elem自己的后继结点为before, 于是before又回到链表 */
  elem->prev = before->prev;
  elem->next = before;

  /* 更新before的前驱结点为elem */
  before->prev = elem;

  intr_set_status(
      old_status); // 关中断之前是开着，那么现在就重新打开中断，如果关着，那么就继续关着
}

/* 添加元素到列表队首,类似栈push操作，添加结点到链表队首，类似于push操作,
 * 参数1是链表的管理结点，参数2是一个新结点 */
void list_push(struct list* plist, struct list_elem* elem)
{
  list_insert_before(plist->head.next, elem); // 在队头插入elem
}

/* 追加元素到链表队尾,类似队列的先进先出操作，添加结点到队尾，实际上就是添加结点到管理结点之前。参数是管理结点与要添加的结点
 */
void list_append(struct list* plist, struct list_elem* elem)
{
  list_insert_before(&plist->tail, elem); // 在队尾的前面插入
}

/* 使元素pelem脱离链表 */
void list_remove(struct list_elem* pelem)
{
  enum intr_status old_status =intr_disable();

  pelem->prev->next = pelem->next;
  pelem->next->prev = pelem->prev;

  intr_set_status(old_status);
}

/* 将链表第一个元素弹出并返回,类似栈的pop操作，参数是链表的管理结点（入口结点）
 */
struct list_elem* list_pop(struct list* plist)
{
  struct list_elem* elem = plist->head.next;
  list_remove(elem);
  return elem;
}

/* 从链表中查找元素obj_elem,成功时返回true,失败时返回false */
bool elem_find(struct list* plist, struct list_elem* obj_elem)
{
  struct list_elem* elem = plist->head.next;
  while (elem != &plist->tail)
  {
    if (elem == obj_elem)
    {
      return true;
    }

    if (elem->next != NULL)
    {
      elem = elem->next;
    }
    else
    {
      put_str("Trail node\r\n");
    }
  }
  return false;
}

/* 把列表plist中的每个元素elem和arg传给回调函数func,
 * arg给func用来判断elem是否符合条件.
 * 本函数的功能是遍历列表内所有元素,逐个判断是否有符合条件的元素。
 * 找到符合条件的元素返回元素指针,否则返回NULL. */
struct list_elem* list_traversal(struct list* plist, operation_func func,
                                 int arg)
{
  struct list_elem* elem = plist->head.next;
  /* 如果队列为空,就必然没有符合条件的结点,故直接返回NULL */
  if (list_empty(plist))
  {
    return NULL;
  }

  while (elem != &plist->tail)
  {
    if (func(elem, arg))
    { // func返回ture则认为该元素在回调函数中符合条件,命中,故停止继续遍历
      return elem;
    } // 若回调函数func返回true,则继续遍历
    elem = elem->next;
  }
  return NULL;
}

/* 返回链表长度，不包含管理结点，参数就是链表的管理结点 */
uint32_t list_len(struct list* plist)
{
  struct list_elem* elem = plist->head.next;
  uint32_t          length = 0;
  while (elem != &plist->tail)
  {
    length++;
    elem = elem->next;
  }
  return length;
}

/* 判断链表是否为空,空时返回true,否则返回false */
bool list_empty(struct list* plist)
{ // 判断队列是否为空
  return (plist->head.next == &plist->tail ? true : false);
}
